package com.mall.service.impl;

import com.google.gson.Gson;
import com.mall.dao.ProductMapper;
import com.mall.enums.ProductStatusEnum;
import com.mall.enums.ResponseEnum;
import com.mall.form.CartAddForm;
import com.mall.form.CartUpdateForm;
import com.mall.pojo.Cart;
import com.mall.pojo.Product;
import com.mall.service.ICartService;
import com.mall.vo.CartProductVo;
import com.mall.vo.CartVo;
import com.mall.vo.ResponseVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * @Author: 黄建
 * @Date: 2020/1/25 17:59
 */
@Service
public class CartServiceImpl implements ICartService {

    private final static String CART_REDIS_KEY_TEMPLATE = "cart_%d";

    @Autowired
    private ProductMapper productMapper;

    @Autowired
    private StringRedisTemplate redisTemplate;

    private Gson gson = new Gson();

    @Override
    public ResponseVo<CartVo> add(Integer uid, CartAddForm form) {
        Integer quantity = 1;

        Product product = productMapper.selectByPrimaryKey(form.getProductId());

        //商品是否存在
        if (product == null) {
            return ResponseVo.error(ResponseEnum.PRODUCT_NOT_EXIST);
        }
        //商品正常在售
        if (product.getStatus().equals(ProductStatusEnum.OFF_SALE.getCode()) || product.getStatus().equals(ProductStatusEnum.DELETE.getCode())) {
            return ResponseVo.error(ResponseEnum.PRODUCT_OFF_SALE_OR_DELETE);
        }

        //商品库存是否充足
        if (product.getStock() <= 0) {
            return ResponseVo.error(ResponseEnum.PRODUCT_STOCK_ERROR);
        }

        String redisKey = String.format(CART_REDIS_KEY_TEMPLATE, uid);

        Cart cart;

        //写入redis

        HashOperations<String, String, Object> opsForHash = redisTemplate.opsForHash();

        String value = (String) opsForHash.get(redisKey, String.valueOf(product.getId()));
        if (StringUtils.isEmpty(value)) {
            //没有该商品，新增
            cart = new Cart(product.getId(), quantity, form.getSelected());
        } else {
            //数量加一
            cart = gson.fromJson(value, Cart.class);
            cart.setProductSelected(form.getSelected());
            cart.setQuantity(cart.getQuantity() + 1);
        }

        opsForHash.put(String.format(CART_REDIS_KEY_TEMPLATE, uid),
                String.valueOf(product.getId()),
                gson.toJson(cart));


        return list(uid);
    }


    public ResponseVo<CartVo> list1(Integer uid) {
        CartVo cartVo = new CartVo();

        HashOperations<String, String, String> opsForHash = redisTemplate.opsForHash();
        String redisKey = String.format(CART_REDIS_KEY_TEMPLATE, uid);

        List<CartProductVo> cartProductVoList = new ArrayList<>();

        Map<String, String> entries = opsForHash.entries(redisKey);

        Boolean selectAll = true;

        BigDecimal cartTotalPrice = BigDecimal.ZERO;

        Integer cartTotalQuantity = 0;

        for (Map.Entry<String, String> entry :
                entries.entrySet()) {
            Integer productId = Integer.valueOf(entry.getKey());
            Cart cart = gson.fromJson(entry.getValue(), Cart.class);
            Product product = productMapper.selectByPrimaryKey(productId);

            CartProductVo cartProductVo = new CartProductVo(product.getId(),
                    cart.getQuantity(), product.getName(), product.getSubtitle(), product.getMainImage(),
                    product.getPrice(), product.getStatus(),
                    product.getPrice().multiply(BigDecimal.valueOf(cart.getQuantity())), product.getStock(), cart.getProductSelected());

            cartProductVoList.add(cartProductVo);

            if (!cart.getProductSelected()) {
                selectAll = false;
            }

            if (cart.getProductSelected()) {
                cartTotalPrice = cartTotalPrice.add(cartProductVo.getProductTotalPrice());
            }
            cartTotalQuantity += cart.getQuantity();

        }
        cartVo.setCartProductVoList(cartProductVoList);
        cartVo.setCartTotalPrice(cartTotalPrice);
        cartVo.setCartTotalQuantity(cartTotalQuantity);
        cartVo.setSelectAll(selectAll);

        return ResponseVo.success(cartVo);
    }

    @Override
    public ResponseVo<CartVo> list(Integer uid) {
        CartVo cartVo = new CartVo();

        HashOperations<String, String, String> opsForHash = redisTemplate.opsForHash();
        String redisKey = String.format(CART_REDIS_KEY_TEMPLATE, uid);

        List<CartProductVo> cartProductVoList = new ArrayList<>();

        List<Integer> productIds = new ArrayList<>();

        List<Cart> carts = new ArrayList<>();

        Boolean selectAll = true;

        Integer cartTotalQuantity = 0;

        BigDecimal cartTotalPrice = BigDecimal.ZERO;

        Map<String, String> entries = opsForHash.entries(redisKey);
        for (Map.Entry<String, String> entry :
                entries.entrySet()) {
            productIds.add(Integer.valueOf(entry.getKey()));
            Cart cart = gson.fromJson(entry.getValue(), Cart.class);
            carts.add(cart);
            if (!cart.getProductSelected()) {
                selectAll = false;
            }
            cartTotalQuantity += cart.getQuantity();
        }

        /*
        1.获取所有productId
        2.获取所有cart
        3.in查询productId
        4.组装cartProductDetail
        5.组装cartVo
         */

        List<Product> products = productMapper.selectByProductIds(productIds);
        if (products.size() == carts.size() && products.size() != 0) {
            for (int i = 0; i < products.size(); i++) {
                Product product = products.get(i);
                Cart cart = carts.get(i);
                CartProductVo cartProductVo = new CartProductVo(product.getId(),
                        cart.getQuantity(), product.getName(), product.getSubtitle(), product.getMainImage(),
                        product.getPrice(), product.getStatus(),
                        product.getPrice().multiply(BigDecimal.valueOf(cart.getQuantity())), product.getStock(), cart.getProductSelected());

                cartProductVoList.add(cartProductVo);
                //计算选中状态的价格
                if (cart.getProductSelected()) {
                    cartTotalPrice = cartTotalPrice.add(cartProductVo.getProductTotalPrice());
                }
            }
        }
        cartVo.setSelectAll(selectAll);
        cartVo.setCartTotalQuantity(cartTotalQuantity);
        cartVo.setCartTotalPrice(cartTotalPrice);
        cartVo.setCartProductVoList(cartProductVoList);

        return ResponseVo.success(cartVo);
    }

    @Override
    public ResponseVo<CartVo> update(Integer uid, Integer productId, CartUpdateForm cartUpdateForm) {
        HashOperations<String, String, String> opsForHash = redisTemplate.opsForHash();
        String redisKey = String.format(CART_REDIS_KEY_TEMPLATE, uid);
        String value = opsForHash.get(redisKey, String.valueOf(productId));

        if (StringUtils.isEmpty(value)) {
            //没有该商品
            return ResponseVo.error(ResponseEnum.CART_PRODUCT_NOT_EXIST);
        }
        //查询到该商品，更新数据
        Cart cart = gson.fromJson(value, Cart.class);
        if (cartUpdateForm.getQuantity() != null && cartUpdateForm.getQuantity() >= 0) {
            cart.setQuantity(cartUpdateForm.getQuantity());
        }
        if (cartUpdateForm.getSelected() != null) {
            cart.setProductSelected(cartUpdateForm.getSelected());
        }
        opsForHash.put(redisKey, String.valueOf(productId), gson.toJson(cart));

        return list(uid);
    }

    @Override
    public ResponseVo<CartVo> delete(Integer uid, Integer productId) {
        HashOperations<String, String, String> opsForHash = redisTemplate.opsForHash();
        String redisKey = String.format(CART_REDIS_KEY_TEMPLATE, uid);
        String value = opsForHash.get(redisKey, String.valueOf(productId));
        if (StringUtils.isEmpty(value)) {
            //没有该商品
            return ResponseVo.error(ResponseEnum.CART_PRODUCT_NOT_EXIST);
        }
        //删除
        opsForHash.delete(redisKey, String.valueOf(productId));

        return list(uid);
    }

    @Override
    public ResponseVo<CartVo> selectAll(Integer uid) {
        HashOperations<String, String, String> opsForHash = redisTemplate.opsForHash();
        String redisKey = String.format(CART_REDIS_KEY_TEMPLATE, uid);

        for (Cart cart: listForCart(uid)) {
            cart.setProductSelected(true);
            opsForHash.put(redisKey,String.valueOf(cart.getProductId()),gson.toJson(cart));
        }
        return list(uid);
    }

    @Override
    public ResponseVo<CartVo> unselectAll(Integer uid) {
        HashOperations<String, String, String> opsForHash = redisTemplate.opsForHash();
        String redisKey = String.format(CART_REDIS_KEY_TEMPLATE, uid);

        for (Cart cart: listForCart(uid)) {
            cart.setProductSelected(false);
            opsForHash.put(redisKey,String.valueOf(cart.getProductId()),gson.toJson(cart));
        }
        return list(uid);
    }

    @Override
    public ResponseVo<Integer> sum(Integer uid) {
        HashOperations<String, String, String> opsForHash = redisTemplate.opsForHash();
        String redisKey = String.format(CART_REDIS_KEY_TEMPLATE, uid);

        Map<String, String> entries = opsForHash.entries(redisKey);

        Integer cartTotalQuantity = 0;

        for (Map.Entry<String, String> entry :
                entries.entrySet()) {
            Cart cart = gson.fromJson(entry.getValue(), Cart.class);
            cart.setProductSelected(false);
            opsForHash.put(redisKey, entry.getKey(), gson.toJson(cart));
            cartTotalQuantity += cart.getQuantity();
        }
        return ResponseVo.success(cartTotalQuantity);
    }

    @Override
    public List<Cart> listForCart(Integer uid) {
        List<Cart> carts = new ArrayList<>();
        HashOperations<String, String, String> opsForHash = redisTemplate.opsForHash();
        String redisKey = String.format(CART_REDIS_KEY_TEMPLATE, uid);

        Map<String, String> entries = opsForHash.entries(redisKey);

        for (Map.Entry<String, String> entry :
                entries.entrySet()) {
            Cart cart = gson.fromJson(entry.getValue(), Cart.class);
            carts.add(cart);
        }
        return carts;
    }
}
